#include "threadPool.h"
#include <assert.h>

char buf[4096];

int makeWorker(threadPool_t *pthreadPool)
{
    // 创建若干个子线程
    for (int i = 0; i < pthreadPool->threadNum; ++i)
    {
        pthread_create(&pthreadPool->tidArr[i], NULL, threadFunc, pthreadPool);
    }
    return 0;
}

char *my_itoa(int value, char *buff, int radix)
{
    assert(buff != NULL);
    int left = 0, index = 0, flag = 0;
    const char *temp = "0123456789abcdefghijklmnopqrstuvwxyz";
    if (value < 0 && radix == 10)
    { //"-"
        buff[index++] = '-';
        value *= -1; // 123
        flag = 1;
    }
    unsigned int unsigned_value = (unsigned int)value; // 将value 从有符号数据类型转换为无符号数据类型

    while (unsigned_value != 0)
    {
        left = unsigned_value % radix;
        // 余数存放buff合适位置存放
        buff[index++] = temp[left]; //-321
        unsigned_value /= radix;
    }

    // 数组元素逆转  1 2 3 4 5
    for (int j = 0; j < (index + 1) / 2; j++)
    { //-321      321
        int temp = buff[j + flag];
        buff[j + flag] = buff[index - j - 1];
        buff[index - j - 1] = temp;
    }
    return buff; // 数组尾巴  \0
}

int modeToStr(mode_t mode, char *str)
{
    // str[0] --> 文件类型
    switch (mode & S_IFMT)
    {
    case S_IFBLK:
        str[0] = 'b';
        break;
    case S_IFCHR:
        str[0] = 'c';
        break;
    case S_IFDIR:
        str[0] = 'd';
        break;
    case S_IFIFO:
        str[0] = 'p';
        break;
    case S_IFLNK:
        str[0] = 'l';
        break;
    case S_IFREG:
        str[0] = '-';
        break;
    case S_IFSOCK:
        str[0] = 's';
        break;
    default:
        str[0] = '?';
        break;
    }
    // str[1] --> str[9] 9位权限
    int i = 0400; // 100 000 000 user read
    if ((mode & i) != 0)
    { // 相当于是如果位为1，&后结果就是1
        str[1] = 'r';
    }
    else
    {
        str[1] = '-';
    }
    i = 0200; // 010 000 000 user write
    if ((mode & i) != 0)
    {
        str[2] = 'w';
    }
    else
    {
        str[2] = '-';
    }
    i = 0100; // 001 000 000 user execute
    if ((mode & i) != 0)
    {
        str[3] = 'x';
    }
    else
    {
        str[3] = '-';
    }
    i = 040; // 100 000 group read
    if ((mode & i) != 0)
    {
        str[4] = 'r';
    }
    else
    {
        str[4] = '-';
    }
    i = 020; // 010 000 group write
    if ((mode & i) != 0)
    {
        str[5] = 'w';
    }
    else
    {
        str[5] = '-';
    }
    i = 010; // 001 000 group execute
    if ((mode & i) != 0)
    {
        str[6] = 'x';
    }
    else
    {
        str[6] = '-';
    }
    i = 04; // 100 other read
    if ((mode & i) != 0)
    {
        str[7] = 'r';
    }
    else
    {
        str[7] = '-';
    }
    i = 02; // 010 other write
    if ((mode & i) != 0)
    {
        str[8] = 'w';
    }
    else
    {
        str[8] = '-';
    }
    i = 01; // 001 other execute
    if ((mode & i) != 0)
    {
        str[9] = 'x';
    }
    else
    {
        str[9] = '-';
    }
    return 0;
}

int ls(int argc, char* argv) {
    // ./mylsl .
    //ARGS_CHECK(argc, 2);
    DIR *dirp;
    if(argc == 1){
        argv = ".";
    }
    char res[4096] = {0};
    char ans[4096] = {0};
    char tmp[32] = {0};
    dirp = opendir(argv);
    memset(&buf, 0, sizeof(buf));
    ERROR_CHECK(dirp, NULL, "opendir");
    char path[1024];
    struct dirent *direntp;
    const char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    while ((direntp = readdir(dirp)) != NULL) {
        struct stat statbuf;
        sprintf(path, "%s%s%s", argv, "/", direntp->d_name);
        int ret = stat(path, &statbuf);
        ERROR_CHECK(ret, -1, "ls");
        struct tm *ptm = localtime(&statbuf.st_mtime);
        char str[20] = {0};
        modeToStr(statbuf.st_mode, str);
        sprintf(res, "%s %s %s %s %s %s %s %s:%s %s"
                , str
                , my_itoa(statbuf.st_nlink, tmp, 10)
                , getpwuid(statbuf.st_uid)->pw_name
                , getgrgid(statbuf.st_gid)->gr_name
                , my_itoa(statbuf.st_size, tmp, 10)
                , month[ptm->tm_mon], my_itoa(ptm->tm_mday, tmp, 10), my_itoa(ptm->tm_hour, tmp, 10), my_itoa(ptm->tm_min, tmp, 10)
                , direntp->d_name);	
        strcat(buf, res);
        strcat(buf, "\n");
    }
    closedir(dirp);
    return 0;
}

int existDir(const char *path)
{
    DIR *pdir = opendir(path);
    if (pdir)
    {
        return 0;
    }
    return -1;
}

int existFile(const char *filename)
{
    int ret = open(filename, O_RDONLY);
    if (ret != -1)
    {
        return 0;
    }
    return -1;
}

void *threadFunc(void *arg)
{
    threadPool_t *pthreadPool = (threadPool_t *)arg;  

    MSG msg;
    while (1)
    {
        int netfd;
        memset(buf, 0, sizeof(buf));
        pthread_mutex_lock(&pthreadPool->taskQueue.mutex);
        // pthread_cleanup_push(cleanupMutex,pthreadPool);
        if (pthreadPool->exitflag == 1)
        {
            printf("I am going to die!\n");
            pthread_mutex_unlock(&pthreadPool->taskQueue.mutex);
            pthread_exit(NULL);
        }
        while (pthreadPool->taskQueue.queueSize == 0)
        {
            // taskEnqueue(&pthreadPool->taskQueue, netfd);
            if (pthreadPool->exitflag == 1)
            {
                printf("I am going to die!\n");
                pthread_mutex_unlock(&pthreadPool->taskQueue.mutex);
                pthread_exit(NULL);
            }
            pthread_cond_wait(&pthreadPool->taskQueue.cond, &pthreadPool->taskQueue.mutex);
        }
        netfd = pthreadPool->taskQueue.pFront->netfd;
        taskDequeue(&pthreadPool->taskQueue);
        pthread_mutex_unlock(&pthreadPool->taskQueue.mutex);

        while (1)
        {
            memset(&buf, 0, sizeof(buf));
            memset(&msg, 0, sizeof(msg));
            recv(netfd, &msg, sizeof(msg), 0); // 接收客户端发来的命令
            printf("msg.command = %s, msg.arg = %s\n", msg.command, msg.arg);
            if (!strcmp(msg.command, "") && !strcmp(msg.arg, ""))
            {
                break;
            }
            int ret = 123456789; // 记录各函数返回值
            switch (msg.cmdType)
            { // 指定任务类型
            case CD:
                ret = chdir(msg.arg);
                if (ret == 0)
                {
                    // 执行cd成功, 返回当前目录
                    getcwd(buf, sizeof(buf));
                    send(netfd, buf, strlen(buf), 0);
                }
                else
                {
                    // 执行cd失败 提示no such file or directory
                    send(netfd, "no such dir!", 13, 0);
                }
                break;

            case LS:
                if (strcmp(msg.arg, "") == 0)
                {
                    ls(1, ""); // ls无参的情况
                }
                else
                {
                    ls(2, msg.arg);
                }
                printf("case LS: buf\n %s\n", buf);
                ret = send(netfd, buf, strlen(buf), 0);
                // 应该还需要把ls的结果发给客户端  下次实现
                break;
            case PUTS:
                recvFile(netfd, msg.arg, 0);
                break;

            case GETS:
                transFile(netfd, msg.arg, 0);
                break;

            case REMOVE:
                ret = unlink(msg.arg);
                if (ret == 0)
                {
                    // 删除成功返回0
                    send(netfd, "remove successfully", 19, 0);
                }
                else
                {
                    // 删除不成功返回-1
                    send(netfd, "remove failed", 13, 0);
                }
                break;
            case PWD:
                // 获取当前路径并发送
                getcwd(buf, sizeof(buf));
                printf("pwd = %s\n", buf);
                ret = send(netfd, buf, strlen(buf), 0);
                printf("ret = %d\n", ret);
                break;
            case MKDIR:
                if (existDir(msg.arg) != -1)
                {
                    // 若客户端传来命令里的目录存在，则不理会
                    send(netfd, "no such dir", 11, 0);
                }
                else
                {
                    // 新建目录
                    mkdir(msg.arg, 0777);
                    send(netfd, "mkdir seccessed", 15, 0);
                }
                break;
            case RMDIR:
                if (existDir(msg.arg) == 0)
                { // 目录存在 可删
                    rmdir(msg.arg);
                    send(netfd, "rmdir seccessed", 15, 0);
                }
                else
                { // 指定目录不存在
                    break;
                }
                break;
            case EXIT:
                // send(netfd, "server is gone",14 , 0);
                goto L1;
                // exit(0);
                // break;
            }
            // close(netfd);
            printf("child thread finished task!\n");
        }
    }
L1:
    printf("client is gone!\n");
}
